<template>
  <label :class="wrapClasses">
        <span :class="checkboxClasses">
            <span :class="innerClasses"></span>
            <input
              v-if="group"
              type="checkbox"
              :class="inputClasses"
              :disabled="disabled"
              :value="label"
              v-model="model"
              :name="name"
              @change="change"
              @focus="onFocus"
              @blur="onBlur">
            <input
              v-else
              type="checkbox"
              :class="inputClasses"
              :disabled="disabled"
              :checked="currentValue"
              :name="name"
              @change="change"
              @focus="onFocus"
              @blur="onBlur">
        </span>
    <slot><span v-if="showSlot">{{ label }}</span></slot>
  </label>
</template>
<script>
import {findComponentUpward, oneOf} from '../../utils/assist';
import Emitter from '../../mixins/emitter';

const prefixCls = 'oolong-checkbox';

export default {
  name: 'oolongCheckbox',
  mixins: [Emitter],
  props: {
    disabled: {
      type: Boolean,
      default: false
    },
    value: {
      type: [String, Number, Boolean],
      default: false
    },
    trueValue: {
      type: [String, Number, Boolean],
      default: true
    },
    falseValue: {
      type: [String, Number, Boolean],
      default: false
    },
    label: {
      type: [String, Number, Boolean]
    },
    indeterminate: {
      type: Boolean,
      default: false
    },
    size: {
      validator(value) {
        return oneOf(value, ['small', 'large', 'default']);
      }
    },
    name: {
      type: String
    }
  },
  data() {
    return {
      model: [],
      currentValue: this.value,
      group: false,
      showSlot: true,
      parent: findComponentUpward(this, 'oolongCheckboxGroup'),
      focusInner: false
    };
  },
  computed: {
    wrapClasses() {
      return [
        `${prefixCls}-wrapper`,
        {
          [`${prefixCls}-group-item`]: this.group,
          [`${prefixCls}-wrapper-checked`]: this.currentValue,
          [`${prefixCls}-wrapper-disabled`]: this.disabled,
          [`${prefixCls}-${this.size}`]: !!this.size
        }
      ];
    },
    checkboxClasses() {
      return [
        `${prefixCls}`,
        {
          [`${prefixCls}-checked`]: this.currentValue,
          [`${prefixCls}-disabled`]: this.disabled,
          [`${prefixCls}-indeterminate`]: this.indeterminate
        }
      ];
    },
    innerClasses() {
      return [
        `${prefixCls}-inner`,
        {
          [`${prefixCls}-focus`]: this.focusInner
        }
      ];
    },
    inputClasses() {
      return `${prefixCls}-input`;
    }
  },
  mounted() {
    this.parent = findComponentUpward(this, 'oolongCheckboxGroup');
    if (this.parent) {
      this.group = true;
    }

    if (this.group) {
      this.parent.updateModel(true);
    } else {
      this.updateModel();
      this.showSlot = this.$slots.default !== undefined;
    }
  },
  methods: {
    change(event) {
      if (this.disabled) {
        return false;
      }

      const checked = event.target.checked;
      this.currentValue = checked;
      const value = checked ? this.trueValue : this.falseValue;
      this.$emit('input', value);

      if (this.group) {
        this.parent.change(this.model);
      } else {
        this.$emit('on-change', value);
        this.dispatch('oolongFormItem', 'on-form-change', value);
      }
    },
    updateModel() {
      this.currentValue = this.value === this.trueValue;
    },
    onBlur() {
      this.focusInner = false;
    },
    onFocus() {
      this.focusInner = true;
    }
  },
  watch: {
    value(val) {
      if (val === this.trueValue || val === this.falseValue) {
        this.updateModel();
      } else {
        // eslint-disable-next-line no-throw-literal
        throw 'Value should be trueValue or falseValue.';
      }
    }
  }
};
</script>
